home *** CD-ROM | disk | FTP | other *** search
/ PC User 2003 December / Australian PC User - December 2003 (CD2).iso / software / apps / files / dwmx2k4.exe / Disk1 / data1.cab / Configuration_En / Translators / TranslationManager.js < prev    next >
Encoding:
JavaScript  |  2003-09-05  |  80.8 KB  |  2,192 lines

  1. //SHARE-IN-MEMORY=true
  2. // Copyright 2000, 2001, 2002, 2003 Macromedia, Inc. All rights reserved.
  3.  
  4. var translatorInfo = new Array();
  5. var lastInStr = "";
  6. var lastOutStr = "";
  7. var lastIndex = "";
  8. var lastDynamicTextFormat = null;
  9. var g_index = "";
  10. var debugMegaLock = false;
  11. var debugTagSpan = false;
  12. var debugTranslationMgr = false;
  13.  
  14. /////////////////////////////////////////////// TranslationManager Class //////////////////////////////////////////////////
  15.  
  16. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  17. // Function : TranslationManager::TranslationManager
  18. // Purpose  : Instantiate this object and call its translate method within your translators 
  19. //        translateMarkup() function.  This will create a translator that utilizes the
  20. //        translation rules defined in the XML participant files containing a
  21. //        translator section.
  22. // Arguments: translatorClass - the translator class as specified by the translators
  23. //        getTranslatorInfo() function.  This name will be used as the 
  24. //        translatorClass attribute of the MM:BeginLock tags.
  25. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  26. function TranslationManager(translatorClass, serverModel, serverLanguage)
  27. {
  28.   // Private Members
  29.   this.docIsLatin1 = null;
  30.   this.inStr = "";
  31.   this.translatorClass = translatorClass;
  32.   this.defaultDirectiveTag = translatorClass;  // the default tag name for directives
  33.   if (serverLanguage)
  34.   {
  35.     this.index = serverModel + ":" + serverLanguage;
  36.   }
  37.   else
  38.   {
  39.     this.index = serverModel;
  40.   }
  41.   g_index = this.index;  // for the sorting function
  42.   this.requery = false;
  43.   this.offsetTagBegin = -1;
  44.   this.offsetTagEnd = -1;
  45.   this.currentTagName = null;
  46.   this.whereToSearch = "";
  47.   this.dynamicTextFormat = dw.getDynamicTextFormat();
  48.   this.params = new Array();
  49.   this.dataSources = new Array();
  50.   this.CFOutput = new Stack(); // Cold Fusion specific to ensure dynamic data within cfoutput tags
  51.   this.translator = new translator; // translator class which interfaces to the Translator Support Library (TSL)
  52.   if (translatorInfo[this.index] == null)
  53.   {
  54.     translatorInfo[this.index] = new Array(); // repository for XML translator information
  55.     translatorInfo[this.index].lookInAllAttributes = false;
  56.     translatorInfo[this.index].lookInAllTags = false;
  57.   }
  58.  
  59.   // Methods to use in identifying dynamic tags and attributes
  60.   this.serverModelAlwaysCheckTag = null;
  61.   this.serverModelAlwaysCheckAttribute = null;
  62.  
  63.   // Methods for constructing whole tag spans
  64.   this.inTagSpan = false;          // currently inside tag span
  65.   this.tagSpan = null;             // contents of tag span thus far
  66.   this.tagSpanRecover = false;     // on second pass through tag span
  67.   this.tagSpanName = null;         // name of tag
  68.   this.tagSpanCounter = null;      // used to match up nested tags
  69.   this.tagSpanParts = null;        // tag+name and tag+* participants
  70.   this.tagSpanSnapshot = null;
  71.   this.tagSpanLastIndex = -1;
  72.  
  73.   // Stack of tags that enclose current code (if there are any)
  74.   this.enclosingTags = new Array();
  75.  
  76.   // Object with methods getTranslation and setTranslation.  If non-null,
  77.   // will be used to cache all tag spans.
  78.   this.tagSpanCache = null;
  79.  
  80.   this.mode = "preview";
  81.   this.inEditMode = false;
  82.   this.editModeEndOffset = -1;
  83.   this.editModeFullCode = null;
  84.   this.editModeFullTranslation = null;
  85.  
  86.   // Megalocks aggregate several separate locked regions into one.
  87.   this.inMegaLock = false;
  88.   this.megaLockCode = null;
  89.   this.megaLockTranslation = null;
  90.   this.megaLockPreCodeOffset = 0;
  91.   this.megaLockSnapshot = null;
  92.  
  93.   // Maintenance for reparsing (when a tag span doesn't match any of the
  94.   // available translations or when parsing in dual-mode)
  95.   this.reparse = false;
  96.   this.reparseSnapshot = null;
  97.  
  98.   this.directives = "";
  99. }
  100.   // public methods
  101.   TranslationManager.prototype.translate              = TM_translate;
  102.   TranslationManager.prototype.notifyXMLChange        = TM_notifyXMLChange;
  103.  
  104.   // public static methods
  105.   TranslationManager.findTagLength                    = TM_findTagLength;
  106.   TranslationManager.getAttributeValue                = TM_getAttributeValue;
  107.   TranslationManager.splitBody                        = TM_splitBody;
  108.  
  109.   // private methods
  110.   TranslationManager.prototype.getTranslatorInfo      = TM_getTranslatorInfo;
  111.   TranslationManager.prototype.getParticipant         = TM_getParticipant;
  112.   TranslationManager.prototype.getDirective           = TM_getDirective;
  113.   TranslationManager.prototype.getAttribute           = TM_getAttribute;
  114.   TranslationManager.prototype.getText                = TM_getText;
  115.   TranslationManager.prototype.getTag                 = TM_getTag;
  116.   TranslationManager.prototype.getData                = TM_getData;
  117.   TranslationManager.prototype.getTokens              = TM_getTokens;
  118.   TranslationManager.prototype.isPattern              = TM_isPattern;
  119.   TranslationManager.prototype.getCurrentTagName      = TM_getCurrentTagName;
  120.   TranslationManager.prototype.getCurrentTag          = TM_getCurrentTag;
  121.   TranslationManager.prototype.translateDirective     = TM_translateDirective;
  122.   TranslationManager.prototype.translateAttribute     = TM_translateAttribute;
  123.   TranslationManager.prototype.translateText          = TM_translateText;
  124.   TranslationManager.prototype.translateTag           = TM_translateTag;
  125.   TranslationManager.prototype.notifyTagBegin         = TM_notifyTagBegin;
  126.   TranslationManager.prototype.notifyTagEnd           = TM_notifyTagEnd;
  127.   TranslationManager.prototype.getCurrentTagOffset    = TM_getCurrentTagOffset;
  128.   TranslationManager.prototype.getParams              = TM_getParams;
  129.   TranslationManager.prototype.searchMatchesCode      = TM_searchMatchesCode;
  130.   TranslationManager.prototype.searchMatchesOpenTag   = TM_searchMatchesOpenTag;
  131.   TranslationManager.prototype.getMatchingParticipant = TM_getMatchingParticipant
  132.   TranslationManager.prototype.startTagSpan           = TM_startTagSpan;
  133.   TranslationManager.prototype.addToTagSpan           = TM_addToTagSpan;
  134.   TranslationManager.prototype.addOpenTagToTagSpan    = TM_addOpenTagToTagSpan;
  135.   TranslationManager.prototype.addCloseTagToTagSpan   = TM_addCloseTagToTagSpan;
  136.   TranslationManager.prototype.finishTagSpan          = TM_finishTagSpan;
  137.   TranslationManager.prototype.correctOutlineIDs      = TM_correctOutlineIDs;
  138.   TranslationManager.prototype.translateTagSpan       = TM_translateTagSpan;
  139.   TranslationManager.prototype.translateTextSpan      = TM_translateTextSpan;
  140.   TranslationManager.prototype.startMegaLock          = TM_startMegaLock;
  141.   TranslationManager.prototype.addToMegaLock          = TM_addToMegaLock;
  142.   TranslationManager.prototype.finishMegaLock         = TM_finishMegaLock;
  143.   TranslationManager.prototype.startEditMode          = TM_startEditMode;
  144.   TranslationManager.prototype.endEditMode            = TM_endEditMode;
  145.   TranslationManager.prototype.setDecoration          = TM_setDecoration;
  146.   TranslationManager.prototype.initialize             = TM_reInitialize;
  147.   TranslationManager.prototype.participantSort        = TM_participantSort;
  148.   TranslationManager.prototype.lookInThisAttribute    = TM_lookInThisAttribute;
  149.   TranslationManager.prototype.alwaysCheckAttribute   = TM_alwaysCheckAttribute;
  150.   TranslationManager.prototype.lookInThisTag          = TM_lookInThisTag;
  151.   TranslationManager.prototype.alwaysCheckTag         = TM_alwaysCheckTag;
  152.   TranslationManager.prototype.lookInTags             = TM_lookInTags;
  153.   TranslationManager.prototype.pushOpenTag            = TM_pushOpenTag;
  154.   TranslationManager.prototype.popCloseTag            = TM_popCloseTag;
  155.   TranslationManager.prototype.prepForReparse         = TM_prepForReparse;
  156.   TranslationManager.prototype.takeSnapshot           = TM_takeSnapshot;
  157.   TranslationManager.prototype.restoreSnapshot        = TM_restoreSnapshot;
  158.  
  159. ///////////////////////////////////////////////
  160. // Function : TM_reInitialize
  161. // Purpose  : Informs the TSL to reinitialize itself
  162. ////////////////////////////////////////////////////////////////////////////
  163. ///////////////////////////////////////////////
  164. function TM_reInitialize()
  165. {
  166.     this.translator.initiate(this.document, this.translatorClass);
  167. }
  168.  
  169. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  170. // Function : TM_translate
  171. // Purpose  : Utilizes dw.scanSourceString to reliably parse through the given HTML string.
  172. // Arguments: the HTML string to translate
  173. // Returns  : the translation string as defined by the rules in the XML participant files
  174. //            containing translator sections.  This string should be returned by the 
  175. //            translators translateMarkup() function.
  176. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  177. function TM_translate(inStr)
  178. {
  179.   if (this.index != lastIndex || inStr != lastInStr || this.dynamicTextFormat != lastDynamicTextFormat)
  180.   {
  181.     this.docIsLatin1 = (dw.getDocumentDOM().getCharSet() == "iso-8859-1");
  182.     this.inStr = inStr;
  183.     this.translator.initiate(inStr, this.translatorClass);
  184.     var callback = new TMCallback(this);
  185.     dreamweaver.scanSourceString(inStr, callback);
  186.     while (this.reparse || this.inTagSpan)
  187.     {
  188.       if (this.inTagSpan)
  189.       {
  190.         this.prepForReparse("tagspan");
  191.         // Restart the translator from the beginning of the tag span (in "recover" state)
  192.         this.inTagSpan = false;
  193.         this.tagSpanRecover = true;
  194.         callback.inTagSpan = false;
  195.       }
  196.       else if (this.inMegaLock)
  197.       {
  198.         this.prepForReparse("megalock");
  199.       }
  200.  
  201.       this.reparse = false;
  202.       if (this.reparseSnapshot)
  203.         this.restoreSnapshot(this.reparseSnapshot);
  204.  
  205.       if (debugTranslationMgr)
  206.           alert("Restarting translator due to " +
  207.             (this.inTagSpan ? "tag span (" : "reparse (") +
  208.             this.reparseSnapshot.offset + ")...\n" + 
  209.             this.inStr);
  210.  
  211.       dreamweaver.scanSourceString(this.inStr, callback);
  212.     }
  213.     if (this.inMegaLock)
  214.     {
  215.         if (debugMegaLock)
  216.             alert("Open mega lock");
  217.         this.finishMegaLock("");
  218.     }
  219.     var outStr = this.translator.getTranslation();
  220.     this.translator.terminate();
  221.     if (inStr.length != outStr.length)
  222.     {
  223.       lastInStr = inStr;
  224.       lastOutStr = outStr;
  225.       lastIndex = this.index;
  226.     }
  227.     lastDynamicTextFormat = this.dynamicTextFormat;
  228.   }
  229.   else
  230.   {
  231.     outStr = lastOutStr;
  232.   }
  233.  
  234.   return outStr;
  235. }
  236.  
  237. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  238. // Function : TM_notifyXMLChanged
  239. // Purpose  : Informs the translator that the translatorInfo needs to be refreshed.
  240. //        Call this when the Participant files translator sections have been modified.
  241. //        Since there is no UI currently provided to define the translation rules,
  242. //        developers will need to restart UltraDev when adding/modifying participant
  243. //        files translator sections.
  244. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  245. function TM_notifyXMLChange() 
  246.   this.requery = true;
  247. }
  248.  
  249. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  250. // Function : TM_prepForReparse
  251. // Purpose  : Sets up the TM for a reparse of a portion of the document.
  252. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  253. function TM_prepForReparse(cause, offset)
  254. {
  255.     this.reparse = true;
  256.     if (cause == "tagspan")
  257.         this.reparseSnapshot = this.tagSpanSnapshot;
  258.     else if (cause == "megalock")
  259.         this.reparseSnapshot = this.megaLockSnapshot;
  260.     else
  261.         this.reparseSnapshot = new Snapshot(this.enclosingTags, offset);
  262. }
  263.  
  264. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  265. // Function : evalPattern
  266. // Purpose    : The JavaScript interpreter needs to do some extra work (in
  267. //          js_PutCallObject) whenever it invokes any function containing
  268. //          an eval statement.  In order to avoid doing that processing
  269. //          every time that TM_getTranslatorInfo is called, the eval
  270. //          statement is wrapped inside this function.
  271. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  272. function evalPattern(pattern)
  273. {
  274.     return eval(pattern);
  275. }
  276.  
  277. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  278. // Function : TM_getTranslatorInfo
  279. // Purpose  : Build the global multi-dimensional array (translatorInfo) representing the 
  280. //        translator information from the XML participant files.
  281. //        Each server model is loaded only once unless requery is set.
  282. //        Note: This is the sole interface between the Translation Manager and the
  283. //        Extension Data Manager (EDM).
  284. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  285. function TM_getTranslatorInfo() 
  286.   if (this.requery || (translatorInfo[this.index].participants == null))
  287.   {
  288.     // TO DO, if this.requery is true, then we need to destroy the objects in
  289.     // translatorInfo so they too will be reloaded on demand.
  290.  
  291.     // Arrays for partitioning participants by type
  292.     translatorInfo[this.index].participants = 1;
  293.     translatorInfo[this.index].directiveParticipants = new Array();
  294.     translatorInfo[this.index].attributeParticipants = new Array();
  295.     translatorInfo[this.index].textParticipants = new Array();
  296.     translatorInfo[this.index].tagOnlyParticipants = new Array();
  297.     translatorInfo[this.index].outerHTMLParticipants = new Array();
  298.  
  299.     var partArry = dw.getExtParticipants("", "translator");
  300.     if (partArry)
  301.     {
  302.       // Sort participants by priority
  303.  
  304.       var sortValue = 500;
  305.       translatorInfo[this.index].sortOrder = new Array();
  306.       for (var i = 0; i < partArry.length; i++)
  307.       {
  308.         var priority = dw.getExtDataValue(partArry[i], "translator", "priority");
  309.         var type = dw.getExtDataValue(partArry[i], "translator", "type");
  310.         if (type == "renderer")
  311.         {
  312.             continue;
  313.         }
  314.  
  315.         if (priority.length)
  316.           translatorInfo[this.index].sortOrder[partArry[i]] = priority.valueOf();
  317.         else
  318.           translatorInfo[this.index].sortOrder[partArry[i]] = sortValue++;
  319.       }
  320.       partArry.sort(this.participantSort);
  321.  
  322.       // Process each participant in turn (collecting its data)
  323.  
  324.       for (var i = 0; i < partArry.length; i++)
  325.       {
  326.         var type = dw.getExtDataValue(partArry[i], "translator", "type");
  327.         if (type == "renderer")
  328.         {
  329.             continue;
  330.         }
  331.         if (translatorInfo[this.index][partArry[i]] == null)
  332.         {
  333.           translatorInfo[this.index][partArry[i]] = new Array();
  334.           var transInfo = translatorInfo[this.index][partArry[i]];
  335.  
  336.           // === TRANSLATIONS ===
  337.  
  338.           var transArry = dw.getExtDataArray(partArry[i], "translator", "translations");
  339.           if (transArry && transArry.length)
  340.           {
  341.             transInfo.translations = new Array();
  342.  
  343.             for (var j = 0; j < transArry.length; j++)
  344.             {
  345.               // Fill in translatorInfo[this.index].???participants and
  346.               // translatorInfo[this.index][partArry[i]][whereToSearch]
  347.               transData.parse(partArry[i], transArry[j], translatorInfo[this.index], this);
  348.             }
  349.           }
  350.  
  351.           // === CONTEXT ===
  352.  
  353.           var context = dw.getExtDataValue(partArry[i], "translator", "context");
  354.           if (context && context.length)
  355.             transInfo.context = context.toLowerCase();
  356.           else
  357.             transInfo.context = null;
  358.  
  359.           // === MODE ===
  360.           var mode = dw.getExtDataValue(partArry[i], "translator", "mode");
  361.           if (mode && mode.length)
  362.             transInfo.mode = mode.toLowerCase();
  363.           else
  364.             transInfo.mode = null;
  365.  
  366.           // === SEARCH PATTERNS ===
  367.  
  368.           var patternArry = dw.getExtDataArray(partArry[i], "translator", "searchPatterns");
  369.           if (patternArry && patternArry.length)
  370.           {
  371.             transInfo.patterns = new Array();
  372.             transInfo.isPatternRE = new Array();
  373.             transInfo.isOptional = new Array();
  374.             transInfo.requiredLocation = new Array();
  375.             transInfo.paramNames = new Array();
  376.             for (var j = 0; j < patternArry.length; j++)
  377.             {
  378.               var pattern = dw.getExtDataValue(partArry[i], "translator", "searchPatterns", patternArry[j]);
  379.  
  380.               if (this.isPattern(pattern))
  381.               {
  382.                 // Any participant with a regular expression in the first search pattern is
  383.                 // going to have to be checked against each attribute in each page
  384.                 if (j == 0 && !translatorInfo[this.index].lookInAllAttributes)
  385.                   if (translatorInfo[this.index].attributeParticipants[partArry[i]])
  386.                     translatorInfo[this.index].lookInAllAttributes = true;
  387.                 transInfo.isPatternRE[patternArry[j]] = true;
  388.                 transInfo.patterns[patternArry[j]] = evalPattern(pattern);
  389.               }
  390.               else
  391.               {
  392.                 // Any participant with a string in the first search pattern is only
  393.                 // going to have to be checked against each attribute in each page if
  394.                 // that string doesn't match one of our predictable patterns
  395.                 if (j == 0 && !translatorInfo[this.index].lookInAllAttributes)
  396.                   if (translatorInfo[this.index].attributeParticipants[partArry[i]])
  397.                     if (!this.alwaysCheckAttribute(pattern))
  398.                       translatorInfo[this.index].lookInAllAttributes = true;
  399.                 transInfo.isPatternRE[patternArry[j]] = false;
  400.                 transInfo.patterns[patternArry[j]] = pattern;
  401.               }
  402.  
  403.               var isOptional =
  404.                 dw.getExtDataValue(partArry[i], "translator", "searchPatterns", patternArry[j], "isOptional");
  405.               transInfo.isOptional[patternArry[j]] = (isOptional.toLowerCase() == "true");
  406.                                   
  407.               var requiredLocation =
  408.                 dw.getExtDataValue(partArry[i], "translator", "searchPatterns", patternArry[j], "requiredLocation").toLowerCase();
  409.               transInfo.requiredLocation[patternArry[j]] = "";
  410.               if (requiredLocation == "leading" ||
  411.                 requiredLocation == "trailing" ||
  412.                 requiredLocation == "opentag" ||
  413.                 requiredLocation == "tagname")
  414.                 transInfo.requiredLocation[patternArry[j]] = requiredLocation;
  415.               var paramNames = dw.getExtDataValue(partArry[i], "translator", "searchPatterns", patternArry[j], "paramNames");
  416.               if (paramNames && paramNames.length)
  417.                 transInfo.paramNames[patternArry[j]] = paramNames;
  418.             }
  419.           }
  420.         }
  421.       }
  422.     }
  423.     this.requery = false;
  424.   }
  425. }
  426.  
  427. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  428. // Function : TM_lookInThisAttribute
  429. // Purpose  : Used within the TM_callback class to see if it necessary to look
  430. //        within this particular attribute to check for a translation rule.
  431. //        This is an optimization that allows us to ignore looping through
  432. //        all participants with translation rules for most attributes.  It 
  433. //        relies on the fact that our current translation rules for attributes
  434. //        all have quicksearches defined (non-regular expression search pattern)
  435. //        that contain certain known character sequences (ie. '<%', '#', '<cf',
  436. //        and '<jsp:').  If a developer extends these any of our translators in 
  437. //        such a way that their quick search pattern does not exist or is not one
  438. //        of these expressions, then this performance boost will not kick in since
  439. //        we will not be able to quickly reject most attributes.
  440. // Arguments: code : this is the attribute value passed into the attribute callback method.
  441. // Returns  : false if we can quickly reject this attribute value (i.e we dont need to 
  442. //        search within the attribute participants for a pattern that matches this code. 
  443. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  444. function TM_lookInThisAttribute(code)
  445. {
  446.   this.getTranslatorInfo();
  447.   if (translatorInfo[this.index].lookInAllAttributes)
  448.     return true;
  449.   else if (this.alwaysCheckAttribute(code))
  450.     return true;
  451.   return false;
  452. }
  453.  
  454.  
  455. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  456. // Function : TM_alwaysCheckAttribute
  457. // Purpose  : Allows server models to specify their own attribute character
  458. //        sequences for the optimization implemented in TM_lookInThisAttribute.
  459. //        See myAlwaysCheckAttribute in JSP.htm for an example.
  460. // Arguments: code = quicksearch pattern or code from TMCallback attribute function
  461. // Returns  : true = try to translate attribute, false = skip attribute
  462. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  463. function TM_alwaysCheckAttribute(code)
  464. {
  465.   if (this.serverModelAlwaysCheckAttribute != null)
  466.     return this.serverModelAlwaysCheckAttribute(code);
  467.   else
  468.     return false;
  469. }
  470.  
  471. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  472. // Function : TM_lookInThisTag
  473. // Purpose  : Used within the TM_callback class to see if it necessary to look
  474. //        within this particular tag to check for a translation rule.
  475. //        This is an optimization that allows us to ignore looping through
  476. //        all participants with translation rules for most tags.  It 
  477. //        relies on the fact that our current translation rules for tags
  478. //        apply only to tags with known prefixes (like "jsp:" or "cf")
  479. //        If a developer adds a translation rule for a tag that doesn't
  480. //        start with one of these prefixes, then this performance boost will
  481. //        not kick in since we will not be able to quickly reject most tags.
  482. // Arguments: tagName
  483. // Returns  : false if we can quickly reject this tag (i.e we dont need to search
  484. //        within the tag participants for a pattern that matches this code).
  485. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  486. function TM_lookInThisTag(tagName)
  487. {
  488.   this.getTranslatorInfo();
  489.   if (translatorInfo[this.index].lookInAllTags)
  490.     return true;
  491.   else if (this.alwaysCheckTag(tagName))
  492.     return true;
  493.   return false;
  494. }
  495.  
  496. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  497. // Function : TM_alwaysCheckTag
  498. // Purpose  : Allows server models to specify their own tag tests for the optimization
  499. //        implemented in TM_lookInThisTag.  See myAlwaysCheckTag in JSP.htm
  500. //        for an example.
  501. // Arguments: tagName
  502. // Returns  : true = try to translate this tag, false = skip this tag
  503. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  504. function TM_alwaysCheckTag(tagName)
  505. {
  506.   if (this.serverModelAlwaysCheckTag != null)
  507.     return this.serverModelAlwaysCheckTag(tagName);
  508.   else
  509.     return false;
  510. }
  511.  
  512. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  513. // Function : TM_lookInTags
  514. // Purpose  : DEPRECATED
  515. // Arguments: 
  516. // Returns  : true if any participant for the current server model contains a tag
  517. //        search.
  518. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  519. function TM_lookInTags()
  520. {
  521.   return translatorInfo[this.index].lookInAllTags;
  522. }
  523.  
  524. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  525. // Function : TM_participantSort
  526. // Purpose  : Sorts participants based on the priority attribute of the translator tag
  527. // Arguments: ptype - the callback location where dw.scanSourceString found the code fragment
  528. //        code - the code fragment to match against the XML patterns
  529. // Returns  : Name of the participant that matches the code segment and location requirement,
  530. //        null if none found.
  531. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  532. function TM_participantSort(part1, part2)
  533. {
  534.   var result = 0;
  535.   var priority1 = translatorInfo[g_index].sortOrder[part1];
  536.   var priority2 = translatorInfo[g_index].sortOrder[part2];
  537.   if (priority1 != priority2)
  538.   {
  539.     if (priority1 < priority2)
  540.     {
  541.       result = -1;
  542.     }
  543.     else
  544.     {
  545.       result = 1;
  546.     }
  547.   }
  548.   return result;
  549. }
  550.  
  551. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  552. // Function : TM_getParticipant
  553. // Purpose  : Find the participant whose search and location specification matches the
  554. //        specified code fragment.
  555. // Arguments: ptype - the callback location where dw.scanSourceString found the code fragment
  556. //        code - the code fragment to match against the XML patterns
  557. // Returns  : Name of the participant that matches the code segment and location requirement,
  558. //        null if none found.
  559. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  560. function TM_getParticipant(pType, code)
  561. {
  562.   var participant = null;
  563.   if (pType == PTYPE_ATTRIBUTE)
  564.   { 
  565.     participant = this.getAttribute(code, TM_getParticipant.arguments[2]);
  566.   }
  567.   else
  568.   {
  569.     if (pType == PTYPE_TAG)
  570.     {
  571.       participant = this.getTag(code);
  572.     }
  573.     else
  574.     {
  575.       if (pType == PTYPE_TEXT)
  576.       {
  577.         participant = this.getText(code);
  578.       }
  579.       else
  580.       {
  581.         if (pType == PTYPE_DIRECTIVE)
  582.         {
  583.           participant = this.getDirective(code);
  584.         }
  585.       }
  586.     }
  587.   }
  588.   return participant;
  589. }
  590.  
  591. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  592. // Function : TM_getDirective
  593. // Purpose  : Find the participant whose translation name is "directive" and pattern 
  594. //        successfuly identifies the specified code segment.
  595. // Arguments: code - directive from dw.scanSourceString directive callback.
  596. // Returns  : Matching participant, otherwise null.
  597. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  598. function TM_getDirective(code)
  599. {
  600.   var participant = null;
  601.   this.getTranslatorInfo();
  602.   var index = "directive";
  603.   var arry = translatorInfo[this.index];
  604.  
  605.   if (arry.directiveParticipants)
  606.   {
  607.     for (var part in arry.directiveParticipants)
  608.     {
  609.       var translations = arry[part].translations;
  610.       if (translations)
  611.       {
  612.         if (translations[index])
  613.         {
  614.           if (this.searchMatchesCode(part, code))
  615.           {
  616.             this.whereToSearch = index;
  617.             participant = part;
  618.             break;
  619.           }
  620.         }
  621.       }
  622.     }
  623.   }
  624.   return participant;
  625. }
  626.  
  627. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  628. // Function : TM_getText
  629. // Purpose  : Find the participant whose translation name is "text" and pattern 
  630. //        successfuly identifies the specified code segment.
  631. // Arguments: code - text span from dw.scanSourceString text callback.
  632. // Returns  : Matching participant, otherwise null.
  633. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  634. function TM_getText(code)
  635. {
  636.   var participant = null;
  637.   this.getTranslatorInfo();
  638.   var index = "text";
  639.   var arry = translatorInfo[this.index];
  640.  
  641.   if (arry.textParticipants)
  642.   {
  643.     for (var part in arry.textParticipants)
  644.     {
  645.       var translations = arry[part].translations;
  646.       if (translations)
  647.       {
  648.         if (translations[index])
  649.         {
  650.           if (this.searchMatchesCode(part, code))
  651.           {
  652.             this.whereToSearch = index;
  653.             participant = part;
  654.             break;
  655.           }
  656.         }
  657.       }
  658.     }
  659.   }
  660.   return participant;
  661. }
  662.  
  663. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  664. // Function : TM_getTag
  665. // Purpose  : Find the participant whose translation name is equivalent to the current tag name
  666. //        or "*", and whose pattern successfuly identifies the specified code segment.
  667. //        Priority is given to participants whose translation name matches the current tag.
  668. //        If no participant is found, then we search for the wild card tag specification "*".
  669. // Arguments: code - tag span collected between the dw.scanSourceString openTagBegin
  670. //        and openTagEnd callbacks and the tag span between the closeTagBegin and closeTagEnd
  671. //        callbacks.
  672. // Returns  : Matching participant, otherwise null.
  673. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  674. function TM_getTag(code)
  675. {
  676.   var participant = null;
  677.   this.getTranslatorInfo();
  678.   var tag = this.getCurrentTagName();
  679.   var index = "tag+" + tag + ":tagonly";
  680.   var index2 = "tag+*:tagonly";
  681.   var arry = translatorInfo[this.index];
  682.  
  683.   if (arry.tagOnlyParticipants)
  684.   {
  685.     for (var part in arry.tagOnlyParticipants)
  686.     {
  687.       var translations = arry[part].translations;
  688.       if (translations)
  689.       {
  690.         if (translations[index])
  691.         {
  692.           if (this.searchMatchesCode(part, code))
  693.           {
  694.             this.whereToSearch = index;
  695.             participant = part;
  696.             break;
  697.           }
  698.         }
  699.         if (!participant)
  700.         {
  701.           if (translations[index2])
  702.           {
  703.             if (this.searchMatchesCode(part, code))
  704.             {
  705.               this.whereToSearch = index2;
  706.               participant = part;
  707.             }
  708.           }
  709.         }
  710.       }
  711.     }
  712.   }
  713.   return participant; 
  714. }
  715.  
  716. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  717. // Function : TM_getAttribute
  718. // Purpose  : Find the participant whose translation name is equivalent to the current 
  719. //        tag+attribute pair or "*+*", and whose pattern successfuly identifies the 
  720. //        specified code segment.
  721. //        Priority is given to participants whose translation name matches the current 
  722. //        tag+attribute pair.
  723. //        If no participant is found, then we search for the wild card tag+attribute
  724. //        specification "*+*".
  725. // Arguments: code - attribute value from dw.scanSourceString attribute callback.
  726. //        attrName - attribute name from dw.scanSourceString attribute callback.
  727. // Returns  : Matching participant, otherwise null.
  728. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  729. function TM_getAttribute(code, attrName)
  730. {
  731.   var participant = null;
  732.   this.getTranslatorInfo();
  733.   var tag = "tag+" + this.getCurrentTagName();
  734.   var attribute = "attribute+" + attrName.toLowerCase();
  735.   var index = tag + ":" + attribute;
  736.   var index2 = tag + ":attribute+*";
  737.   var index3 = "tag+*:attribute+*";
  738.   var arry = translatorInfo[this.index];
  739.  
  740.   if (arry.attributeParticipants)
  741.   {
  742.     for (var part in arry.attributeParticipants)
  743.     {
  744.       var translations = arry[part].translations;
  745.       if (translations)
  746.       {
  747.         if (translations[index])
  748.         {
  749.           // Look for specific tag + attribute matches first
  750.           if (this.searchMatchesCode(part, code))
  751.           {
  752.             this.whereToSearch = index;
  753.             participant = part;
  754.             break;
  755.           }
  756.         }
  757.         if (!participant)
  758.         {
  759.           if (translations[index2])
  760.           {
  761.             if (this.searchMatchesCode(part, code))
  762.             {
  763.               this.whereToSearch = index2;
  764.               participant = part;
  765.             }
  766.           }
  767.         }
  768.         if (!participant)
  769.         {
  770.           if (translations[index3])
  771.           {
  772.             if (this.searchMatchesCode(part, code))
  773.             {
  774.               this.whereToSearch = index3;
  775.               participant = part;
  776.             }
  777.           }
  778.         }
  779.       }
  780.     }
  781.   }
  782.   return participant;
  783. }
  784.  
  785.  
  786. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  787. // Function : TM_getParams
  788. // Purpose  : pulls parameters out of regular expression match
  789. // Arguments: params - array of params to add to
  790. //            paramNames - comma delimited list of param names
  791. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  792. function TM_getParams(params, paramNames, doEncode)
  793. {
  794.   if (paramNames && paramNames.length)
  795.   {
  796.     var paramArry = paramNames.split(",");
  797.     if (paramArry[0] && paramArry[0].length)
  798.     {
  799.       params[paramArry[0]] = RegExp.$1;
  800.       if (doEncode)
  801.         params[paramArry[0]] = dw.latin1ToNative(params[paramArry[0]]);
  802.     }
  803.     if (paramArry[1] && paramArry[1].length)
  804.     {
  805.       params[paramArry[1]] = RegExp.$2;
  806.       if (doEncode)
  807.         params[paramArry[1]] = dw.latin1ToNative(params[paramArry[1]]);
  808.     }
  809.     if (paramArry[2] && paramArry[2].length)
  810.     {
  811.       params[paramArry[2]] = RegExp.$3;
  812.       if (doEncode)
  813.         params[paramArry[2]] = dw.latin1ToNative(params[paramArry[2]]);
  814.     }
  815.     if (paramArry[3] && paramArry[3].length)
  816.     {
  817.       params[paramArry[3]] = RegExp.$4;
  818.       if (doEncode)
  819.         params[paramArry[3]] = dw.latin1ToNative(params[paramArry[3]]);
  820.     }
  821.     if (paramArry[4] && paramArry[4].length)
  822.     {
  823.       params[paramArry[4]] = RegExp.$5;
  824.       if (doEncode)
  825.         params[paramArry[4]] = dw.latin1ToNative(params[paramArry[4]]);
  826.     }
  827.     if (paramArry[5] && paramArry[5].length)
  828.     {
  829.       params[paramArry[5]] = RegExp.$6;
  830.       if (doEncode)
  831.         params[paramArry[5]] = dw.latin1ToNative(params[paramArry[5]]);
  832.     }
  833.     if (paramArry[6] && paramArry[6].length)
  834.     {
  835.       params[paramArry[6]] = RegExp.$7;
  836.       if (doEncode)
  837.         params[paramArry[6]] = dw.latin1ToNative(params[paramArry[6]]);
  838.     }
  839.     if (paramArry[7] && paramArry[7].length)
  840.     {
  841.       params[paramArry[7]] = RegExp.$8;
  842.       if (doEncode)
  843.         params[paramArry[7]] = dw.latin1ToNative(params[paramArry[7]]);
  844.     }
  845.     if (paramArry[8] && paramArry[8].length)
  846.     {
  847.       params[paramArry[8]] = RegExp.$9;
  848.       if (doEncode)
  849.         params[paramArry[8]] = dw.latin1ToNative(params[paramArry[8]]);
  850.     }
  851.   }
  852. }
  853.  
  854.  
  855. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  856. // Function : TM_searchMatchesOpenTag
  857. // Purpose : determines whether the specified code matches the search patterns with
  858. //           requiredLocation="opentag".  This can be used to eliminate some tag spans
  859. //           from consideration before we bother collecting the whole tag span.
  860. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  861. function TM_searchMatchesOpenTag(part, code)
  862. {
  863.   var found = true;
  864.   var arry = translatorInfo[this.index][part];
  865.  
  866.   if (arry.context)
  867.   {
  868.     var top = null;
  869.     if (this.enclosingTags.length > 0)
  870.       top = this.enclosingTags[this.enclosingTags.length-1];
  871.     if (arry.context != top)
  872.       return false;
  873.   }
  874.  
  875.   if (arry.mode)
  876.   {
  877.     if (arry.mode != this.mode)
  878.       return false;
  879.   }
  880.  
  881.   if (arry.patterns)
  882.   {
  883.     for (var patternName in arry.patterns)
  884.     {
  885.       if (arry.requiredLocation[patternName] == "opentag")
  886.       {
  887.         var isRE = arry.isPatternRE[patternName];
  888.         var pattern = arry.patterns[patternName];
  889.         if (!isRE)
  890.         {
  891.           var offset = code.indexOf(pattern);
  892.         }
  893.         else
  894.         {
  895.           if (this.docIsLatin1)
  896.           {
  897.             code = dw.nativeToLatin1(code);
  898.           }
  899.           var offset = code.search(pattern);
  900.         }
  901.         if (offset == -1 && !arry.isOptional[patternName])
  902.         {
  903.           found = false;
  904.           break;
  905.         }
  906.       }
  907.       else if (arry.requiredLocation[patternName] == "tagname")
  908.       {
  909.         var tagName = this.currentTagName;
  910.         var isRE = arry.isPatternRE[patternName];
  911.         var pattern = arry.patterns[patternName];
  912.         if (!isRE)
  913.         {
  914.           var offset = tagName.indexOf(pattern);
  915.         }
  916.         else
  917.         {
  918.           if (this.docIsLatin1)
  919.           {
  920.             tagName = dw.nativeToLatin1(tagName);
  921.           }
  922.           var offset = tagName.search(pattern);
  923.         }
  924.         if (offset == -1 && !arry.isOptional[patternName])
  925.         {
  926.           found = false;
  927.           break;
  928.         }
  929.       }
  930.     }
  931.   }
  932.  
  933.   return found;
  934. }
  935.  
  936. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  937. // Function : TM_searchMatchesCode
  938. // Purpose  : determines weather the specified code satisfies the search criteria defined
  939. //        within the XML participant translator, patterns section.
  940. //        Multiple ordered searches supported.
  941. // Arguments: part - participant name
  942. //        code - code fragment to run patterns agains
  943. // Returns  : true if match, false otherwise
  944. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  945. function TM_searchMatchesCode(part, code)
  946. {
  947.   var found = false;
  948.   var params = new Array();
  949.   var arry = translatorInfo[this.index][part];
  950.  
  951.   if (arry.context)
  952.   {
  953.     var top = null;
  954.     if (this.enclosingTags.length > 0)
  955.       top = this.enclosingTags[this.enclosingTags.length-1];
  956.     if (arry.context != top)
  957.       return false;
  958.   }
  959.  
  960.   if (arry.mode)
  961.   {
  962.     if (arry.mode != this.mode)
  963.       return false;
  964.   }
  965.  
  966.   if (arry.patterns)
  967.   {
  968.     for (var patternName in arry.patterns)
  969.     {
  970.       var isRE = arry.isPatternRE[patternName];
  971.       var pattern = arry.patterns[patternName];
  972.       if (!isRE)
  973.       {
  974.         if (arry.requiredLocation[patternName] == "")
  975.         {
  976.           var offset = code.indexOf(pattern);
  977.         }
  978.         else
  979.         {
  980.           if (arry.requiredLocation[patternName] == "leading")
  981.           {
  982.             var offset = this.inStr.substr(0, this.getCurrentTagOffset()).indexOf(pattern);
  983.           }
  984.           else
  985.           {
  986.             if (arry.requiredLocation[patternName] == "trailing")
  987.             {
  988.               var offset = this.inStr.substr(this.getCurrentTagOffset() + code.length).indexOf(pattern);
  989.             }
  990.             else
  991.             {
  992.               if (arry.requiredLocation[patternName] == "opentag")
  993.               {
  994.                 var tagLength = TranslationManager.findTagLength(code);
  995.                 if (tagLength != -1)
  996.                   var offset = code.substr(0, tagLength).indexOf(pattern);
  997.               }
  998.               else
  999.               {
  1000.                 if (arry.requiredLocation[patternName] == "tagname")
  1001.                 {
  1002.                   var offset = this.currentTagName.indexOf(pattern);
  1003.                 }
  1004.               }
  1005.             }
  1006.           }
  1007.         }
  1008.       }
  1009.       else
  1010.       {
  1011.         if (arry.requiredLocation[patternName] == "")
  1012.         {
  1013.           if (this.docIsLatin1)
  1014.           {
  1015.             code = dw.nativeToLatin1(code);
  1016.           }
  1017.           var offset = code.search(pattern);
  1018.           if (offset != -1)
  1019.           {
  1020.             var paramNames = arry.paramNames[patternName];
  1021.             this.getParams(params, paramNames, this.docIsLatin1);
  1022.           }
  1023.         }
  1024.         else
  1025.         {
  1026.           if (arry.requiredLocation[patternName] == "leading")
  1027.           {
  1028.             var offset = this.inStr.substr(0, this.getCurrentTagOffset()).search(pattern);
  1029.           }
  1030.           else
  1031.           {
  1032.             if (arry.requiredLocation[patternName] == "trailing")
  1033.             {
  1034.               var offset = this.inStr.substr(this.getCurrentTagOffset() + code.length).search(pattern);
  1035.             }
  1036.             else
  1037.             {
  1038.               if (arry.requiredLocation[patternName] == "opentag")
  1039.               {
  1040.                 var tagLength = TranslationManager.findTagLength(code);
  1041.                 if (tagLength != -1)
  1042.                 {
  1043.                   var tagCode = code.substr(0, tagLength);
  1044.  
  1045.                   if (this.docIsLatin1)
  1046.                   {
  1047.                     tagCode = dw.nativeToLatin1(tagCode);
  1048.                   }
  1049.                   var offset = tagCode.search(pattern);
  1050.                   if (offset != -1)
  1051.                   {
  1052.                     var paramNames = arry.paramNames[patternName];
  1053.                     this.getParams(params, paramNames, this.docIsLatin1);
  1054.                   }
  1055.                 }
  1056.               }
  1057.               else
  1058.               {
  1059.                 if (arry.requiredLocation[patternName] == "tagname")
  1060.                 {
  1061.                   var tagName = this.currentTagName;
  1062.                   if (this.docIsLatin1)
  1063.                   {
  1064.                     tagName = dw.nativeToLatin1(tagName);
  1065.                   }
  1066.                   var offset = tagName.search(pattern);
  1067.                   if (offset != -1)
  1068.                   {
  1069.                     var paramNames = arry.paramNames[patternName];
  1070.                     this.getParams(params, paramNames, this.docIsLatin1);
  1071.                   }
  1072.                 }
  1073.               }
  1074.             }
  1075.           }
  1076.         }
  1077.       }
  1078.  
  1079.       if (offset != -1)
  1080.       {
  1081.         found = true;       
  1082.       }
  1083.       else
  1084.       {
  1085.         if (!arry.isOptional[patternName])
  1086.         {
  1087.           found = false;
  1088.           break;
  1089.         }
  1090.       }
  1091.     }
  1092.   }
  1093.   this.params = params;
  1094.  
  1095.   return found;
  1096. }
  1097.  
  1098. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1099. // Function : TM_getData
  1100. // Purpose  : Retreive the translation information for the given participant.  
  1101. //        Token substitution provided using the specified code fragment.
  1102. // Arguments: part - participant name
  1103. //        code - code for which participant was located
  1104. // Returns  : transData structure which contains the openTag, closeTag, display, attributes, etc.
  1105. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1106. function TM_getData(part, code, attrName)
  1107. {
  1108.   var data = null;
  1109.   if (part)
  1110.   {
  1111.     var whereToSearch = this.whereToSearch;
  1112.     var arry = translatorInfo[this.index][part].translations;
  1113.     if (arry)
  1114.     {
  1115.       if (arry[whereToSearch])
  1116.       {
  1117.         data = transData.copy(arry[whereToSearch].data);
  1118.         var tokens = this.getTokens(part, code, attrName);
  1119.         data.replaceTokens(tokens);
  1120.       }
  1121.     }
  1122.   }
  1123.   return data;
  1124. }
  1125.  
  1126. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1127. // Function : TM_getTokens(part)
  1128. // Purpose  : retreive the translation token patterns for the specified participant
  1129. // Arguments: part - participant
  1130. // Returns  : An array indexed by the token names, containing the token patterns
  1131. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1132. function TM_getTokens(part, code, attrName)
  1133. {
  1134.   var tokens = new Array();
  1135.   if (attrName && attrName != "")
  1136.   {
  1137.     tokens["attr"] = attrName;
  1138.   }
  1139.   for (var paramName in this.params)
  1140.   {
  1141.     tokens[paramName] = this.params[paramName];
  1142.   }
  1143.   return tokens;
  1144. }
  1145. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1146. // Function : TM_isPattern
  1147. // Purpose  : determines whether a string is a regular expression
  1148. // Arguments: pattern - regular expression or quick search expression (locate using indexOf)
  1149. // Returns  : true if regular expression, false otherwise
  1150. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1151. function TM_isPattern(pattern)
  1152. {
  1153.   if (pattern.charAt(0) == "/")
  1154.   {
  1155.     return true;
  1156.   }
  1157.   return false;
  1158. }
  1159.  
  1160. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1161. // Function : TM_getCurrentTagName
  1162. // Purpose  : Get the name of the active tag.  Used from openTagEnd, closeTagEnd, and
  1163. //        attribute callbacks.
  1164. // Arguments: Pass in optional attribute offset, when called from attribute callback.
  1165. // Returns  : Active tag name;
  1166. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1167. function TM_getCurrentTagName()
  1168. {
  1169.   return this.currentTagName;
  1170. }
  1171.  
  1172. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1173. // Function : TM_getCurrentTag
  1174. // Purpose  : returns active tag - example <cfoutput querry-"">
  1175. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1176. function TM_getCurrentTag()
  1177. {
  1178.   var currTag = "";
  1179.   if ((this.offsetTagBegin >= 0) && (this.offsetTagEnd >= 0))
  1180.   {
  1181.     currTag = this.inStr.substr(this.offsetTagBegin, this.offsetTagEnd - this.offsetTagBegin);
  1182.   }
  1183.   return currTag;
  1184. }
  1185.  
  1186. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1187. // Function : TM_getCurrentTagOffset
  1188. // Purpose  : returns offset of beginning of active tag
  1189. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1190. function TM_getCurrentTagOffset()
  1191. {
  1192.   return this.offsetTagBegin;
  1193. }
  1194.  
  1195. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1196. // Function : TM_notifyTagBegin
  1197. // Purpose  : returns active tag
  1198. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1199. function TM_notifyTagBegin(tag, offset)
  1200. {
  1201.   this.currentTagName = tag.toLowerCase();
  1202.   this.offsetTagBegin = offset;
  1203. }
  1204.  
  1205. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1206. // Function : TM_notifyTagEnd
  1207. // Purpose  : returns active tag
  1208. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1209. function TM_notifyTagEnd(offset)
  1210. {
  1211.   this.offsetTagEnd = offset;
  1212.   return this.getCurrentTag();
  1213. }
  1214.  
  1215. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1216. // Function : TM_translateDirective
  1217. // Purpose  : translate the directive given the translation rules (utilizes the dependent search criteria info)
  1218. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1219. function TM_translateDirective(code, offset, trans)
  1220. {
  1221.   var origPosition = this.translator.getPosition();
  1222.   var result = "";
  1223.   if (trans)
  1224.   {
  1225.     result = this.translator.translateDirective(code, offset, trans.participant, trans.type, trans.openTag, trans.closeTag, trans.attributes, trans.display, trans.lockAttributes);
  1226.   }
  1227.   else if (this.defaultDirectiveTag != this.translatorClass)
  1228.   {
  1229.     result = this.translator.translateDirective(code, offset, "script", "", this.defaultDirectiveTag, this.defaultDirectiveTag, "", "", "");
  1230.   }
  1231.   else
  1232.   {
  1233.     result = this.translator.translateDirective(code, offset, "script", "", "", "", "", "", "");
  1234.   }
  1235.   if (this.inMegaLock)
  1236.   {
  1237.     var preCode = this.inStr.substr(origPosition, offset-origPosition);
  1238.     this.addToMegaLock(preCode, code, result);
  1239.   }
  1240.   else if (this.inEditMode)
  1241.   {
  1242.     this.editModeFullTranslation.add(result);
  1243.   }
  1244. }
  1245.  
  1246. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1247. // Function : TM_translateText
  1248. // Purpose  : translate the text given the translation rules
  1249. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1250. function TM_translateText(code, offset, trans)
  1251. {
  1252.   var origPosition = this.translator.getPosition();
  1253.   var result = new Object();
  1254.   result.reparse = false;
  1255.   result.translation = "";
  1256.   if (trans)
  1257.   {
  1258.     if (trans.insertBefore)
  1259.     {
  1260.       result.translation += this.translator.translateText("", offset, trans.participant, "as is", "", "", "", trans.insertBefore, "");
  1261.     }
  1262.  
  1263.     result.translation += this.translator.translateText(code, offset, trans.participant, trans.type, trans.openTag, trans.closeTag, trans.attributes, trans.display, trans.lockAttributes);
  1264.  
  1265.     if (trans.insertAfter)
  1266.     {
  1267.       result.translation += this.translator.translateText("", offset+code.length, trans.participant, "as is", "", "", "", trans.insertAfter, "");
  1268.     }
  1269.     if (trans.reparse)
  1270.     {
  1271.         result.reparse = true;
  1272.         result.useEditMode = trans.useEditMode;
  1273.     }
  1274.   }
  1275.   else
  1276.   {
  1277.     result.translation = this.translator.translateText(code, offset, "", "", "", "", "", "", "");
  1278.   }
  1279.   if (this.inMegaLock)
  1280.   {
  1281.     var preCode = this.inStr.substr(origPosition, offset-origPosition);
  1282.     this.addToMegaLock(preCode, code, result.translation);
  1283.   }
  1284.   else if (this.inEditMode)
  1285.   {
  1286.     this.editModeFullTranslation.add(result);
  1287.   }
  1288.   return result;
  1289. }
  1290.  
  1291. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1292. // Function : TM_translateAttribute
  1293. // Purpose  : translate the attribute given the translation rules
  1294. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1295. function TM_translateAttribute(code, name, trans)
  1296. {
  1297.   if (trans)
  1298.   {
  1299.     if ((this.translatorClass == "MM_CFML") && ((trans.type == "dynamic data") || (trans.type == "dynamic image")) && trans.participant != "DynamicAttribute")
  1300.     {
  1301.       if (this.CFOutput.IsEmpty())
  1302.       {
  1303.         // Need to enforce that cfoutput tags surround the dynamic data
  1304.         if (code.search(/<cfoutput\s*>/i) == -1 || code.search(/<\/cfoutput\s*>/i) == -1)
  1305.         {
  1306.           trans = null;
  1307.         }
  1308.       }
  1309.     }
  1310.   }
  1311.   if (trans)
  1312.   {
  1313.     this.translator.translateAttribute(code, name, trans.type, trans.attributes);
  1314.   }
  1315. }
  1316.  
  1317. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1318. // Function : evalExternalFunction
  1319. // Purpose    : The JavaScript interpreter needs to do some extra work (in
  1320. //          js_PutCallObject) whenever it invokes any function containing
  1321. //          an eval statement.  In order to avoid doing that processing
  1322. //          every time that TM_translateTag is called, the eval
  1323. //          statement is wrapped inside this function.
  1324. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1325. function evalExternalFunction(funcName, code, transMgr)
  1326. {
  1327.   var functionCall = funcName + "(code, transMgr);";
  1328.   return eval(functionCall);
  1329. }
  1330.  
  1331. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1332. // Function : TM_translateTag
  1333. // Purpose  : translate the tag given the translation rules
  1334. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1335. function TM_translateTag(code, offset, trans)
  1336. {
  1337.   var origPosition = this.translator.getPosition();
  1338.   var translation = "";
  1339.   if (trans && trans.type == "external")
  1340.   {
  1341.     trans = evalExternalFunction(trans.display, code, this);
  1342.   }
  1343.  
  1344.   if (trans && trans.beginMegaLock)
  1345.   {
  1346.     this.startMegaLock(offset);
  1347.   }
  1348.  
  1349.   if (trans)
  1350.   {
  1351.     if (trans.insertBefore)
  1352.     {
  1353.       translation += this.translator.translateText("", offset, trans.participant, "as is", "", "", "", trans.insertBefore, "");
  1354.     }
  1355.  
  1356.     translation += this.translator.translateTag(code, offset, trans.participant, trans.type, trans.openTag, trans.closeTag, trans.attributes, trans.display, trans.lockAttributes);
  1357.  
  1358.     if (trans.insertAfter)
  1359.     {
  1360.       translation += this.translator.translateText("", offset+code.length, trans.participant, "as is", "", "", "", trans.insertAfter, "");
  1361.     }
  1362.   }
  1363.   else
  1364.   {
  1365.     translation = this.translator.translateTag(code, offset, "", "", "", "", "", "", "");
  1366.   }
  1367.  
  1368.   if (this.inMegaLock)
  1369.   {
  1370.     var preCode = this.inStr.substr(origPosition, offset-origPosition);
  1371.     this.addToMegaLock(preCode, code, translation);
  1372.   }
  1373.   else if (this.inEditMode)
  1374.   {
  1375.     this.editModeFullTranslation.add(translation);
  1376.   }
  1377.  
  1378.   if (trans && trans.endMegaLock)
  1379.   {
  1380.     translation = this.finishMegaLock(trans.lockAttributes);
  1381.   }
  1382.  
  1383.   var endOffset = offset + code.length;
  1384.   if (this.inEditMode && (endOffset >= this.editModeEndOffset))
  1385.   {
  1386.     this.endEditMode();
  1387.   }
  1388. }
  1389.  
  1390. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1391. // Function : TM_findTagLength
  1392. // Purpose : look ahead and find the ">" that matches this "<".
  1393. // Ignore any script blocks (e.g. <% %>) you find on the way.
  1394. // Return the length of the tag.
  1395. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1396. function TM_findTagLength(searchString)
  1397. {
  1398.   // Counter to match pairs of < and >.  Starts at 1
  1399.   // because we start looking after the first <.
  1400.   var counter = 1;
  1401.  
  1402.   // Start after the first <.  Stop after the matching >.
  1403.   for (var i = 1; i < searchString.length && counter > 0; i++)
  1404.   {
  1405.     if (searchString[i] == '<')
  1406.     counter++;
  1407.     else if (searchString[i] == '>')
  1408.     counter--;
  1409.   }
  1410.  
  1411.   if (i == searchString.length && counter > 0)
  1412.   return -1;
  1413.   else
  1414.     return i;
  1415. }
  1416.  
  1417. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1418. // Function : TM_getAttributeValue
  1419. // Purpose  : pull the ID attribute for the current tag
  1420. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1421. function TM_getAttributeValue(code, attrName)
  1422. {
  1423.   var tagLength = TranslationManager.findTagLength(code);
  1424.   var tag = code.substr(0, tagLength);
  1425.  
  1426.   var value = "";
  1427.   var expression;
  1428.  
  1429.   // name="value"
  1430.   expression = new RegExp(attrName + "\\s*=\\s*\"(((<%.*?%>)|[^<\">])*)\"", "i");
  1431.   if (tag.match(expression))
  1432.     value = RegExp.$1;
  1433.  
  1434.   // name='value'
  1435.   expression = new RegExp(attrName + "\\s*=\\s*'(((<%.*?%>)|[^<'>])*)'", "i");
  1436.   if (value == "" && tag.match(expression))
  1437.     value = RegExp.$1;
  1438.  
  1439.   // name=value
  1440.   expression = new RegExp(attrName + "\\s*=\\s*(((<%.*?%>)|[^ \t\n<\"'>])*)", "i");
  1441.   if (value == "" && tag.match(expression))
  1442.     value = RegExp.$1;
  1443.  
  1444.   return value;
  1445. }
  1446.  
  1447. ///////////////////////////////////////////////////////////////////////////
  1448. // Function : TM_splitBody
  1449. // Purpose  : Static function to locate the contents of the <body>
  1450. // tag and split the document at its boundaries.  It will only attempt
  1451. // this split if the document has a single pair of <body> tags.  Some
  1452. // server models can use this to skip over the tags outside the body
  1453. // (which don't need to be translated).
  1454. ///////////////////////////////////////////////////////////////////////////
  1455. function TM_splitBody(inStr)
  1456. {
  1457.     var result = new Object();
  1458.  
  1459.     result.preInStr = "";
  1460.     result.inStr = inStr;
  1461.     result.postInStr = "";
  1462.   
  1463.   var callback = new Object();
  1464.   callback.openTagCount = 0;
  1465.   callback.closeTagCount = 0;
  1466.   callback.innerStart = -1;
  1467.   callback.innerEnd = -1;
  1468.   callback.openTagBegin = new Function("tag,offset","if (tag.toUpperCase() == \"BODY\") { this.openTagCount++; }");
  1469.   callback.openTagEnd = new Function("offset","if (this.openTagCount == 1 && this.innerStart == -1) { this.innerStart = offset; }");
  1470.   callback.closeTagBegin = new Function("tag,offset","if (tag.toUpperCase() == \"BODY\") { this.innerEnd = offset; this.closeTagCount++; }");
  1471.  
  1472.   dw.scanSourceString(inStr, callback);
  1473.  
  1474.   if (callback.innerStart >= 0 && callback.innerEnd >= 0 && 
  1475.       callback.openTagCount == 1 && callback.closeTagCount == 1)
  1476.   {
  1477.     result.preInStr = inStr.substring(0, callback.innerStart);
  1478.     result.postInStr = inStr.substring(callback.innerEnd);
  1479.     result.inStr = inStr.substring(callback.innerStart, callback.innerEnd);
  1480.  
  1481.     // DEBUG DWfile.write("C:\\TM_splitBody.txt", "preInStr = " + result.preInStr + "\r\n\r\npostInStr = " + result.postInStr + "\r\n\r\ninStr = " + result.inStr);
  1482.   }
  1483.   else
  1484.   {
  1485.    // DEBUG DWfile.write("C:\\TM_splitBody.txt", "failed " + callback.openTagCount + ", " + callback.closeTagCount);
  1486.   }
  1487.  
  1488.     return result;
  1489. }
  1490.  
  1491. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1492. // Function : TM_translateTagSpan
  1493. // Purpose  : translate the tag span given the translation rules 
  1494. // Tag span defined to be a span of the document from the open tag to its close tag
  1495. // For example <cfoutput>#a.b#</cfoutput> is a tag span
  1496. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1497. function TM_translateTagSpan(code, offset, trailingFormat)
  1498. {
  1499.   if (this.tagSpanRecover)
  1500.   {
  1501.     this.tagSpanRecover = false;
  1502.     return false;
  1503.   }
  1504.  
  1505.   var tag = this.getCurrentTagName();
  1506.   tag = tag.toLowerCase();
  1507.   this.getTranslatorInfo();
  1508.   
  1509.   var index = "tag+" + tag + ":all";
  1510.   var index2 = "tag+*:all";
  1511.   var arry = translatorInfo[this.index];
  1512.  
  1513.   var inTagSpan = false;
  1514.   
  1515.   var possibleParticipants = null;
  1516.  
  1517.   if (arry.outerHTMLParticipants)
  1518.   {
  1519.     for (var part in arry.outerHTMLParticipants)
  1520.     {
  1521.       if (!arry[part].mode || arry[part].mode == this.mode)
  1522.       {
  1523.         var translations = arry[part].translations;
  1524.         if (translations)
  1525.         {
  1526.           // Check context, mode, and any search patterns with requiredLocation="openTag" or "tagName"
  1527.           if ((translations[index] || translations[index2]) && this.searchMatchesOpenTag(part, code))
  1528.           {
  1529.             if (possibleParticipants == null)
  1530.               possibleParticipants = new Array();
  1531.             possibleParticipants.push(part);
  1532.           }
  1533.         }
  1534.       }
  1535.     }
  1536.   }
  1537.  
  1538.   if (possibleParticipants != null)
  1539.   {
  1540.     this.startTagSpan(tag, offset - code.length, possibleParticipants);
  1541.     inTagSpan = true;
  1542.   }
  1543.  
  1544.   return inTagSpan;
  1545. }
  1546.  
  1547. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1548. // Function : TM_startTagSpan
  1549. // Purpose  : Enter the tag span state.  All new tags and text will go into
  1550. // the current tag span
  1551. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1552.  
  1553. function TM_startTagSpan(tagName, offset, participants)
  1554. {
  1555.   if (debugTagSpan)
  1556.     alert("startTagSpan..." + tagName);
  1557.   this.tagSpan = new QuickString();
  1558.   this.inTagSpan = true;
  1559.   this.tagSpanName = tagName;
  1560.   this.tagSpanCounter = 0;
  1561.   this.tagSpanParts = participants;
  1562.   this.tagSpanSnapshot = new Snapshot(this.enclosingTags, offset);
  1563. }
  1564.  
  1565. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1566. // Function : TM_addToTagSpan
  1567. // Purpose  : Add text to the current tag span.
  1568. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1569.  
  1570. function isWhiteSpace(x)
  1571. {
  1572.   return x == '\r' || x == '\n' || x == '\t' || x == ' ';
  1573. }
  1574.  
  1575. function TM_addToTagSpan(code, offset)
  1576. {
  1577.   var whitespace = "";
  1578.   if (this.tagSpanLastIndex != -1)
  1579.   {
  1580.     // White space and invalid tags don't generate a call to translateText, so
  1581.     // we need to slurp in any text that's occured since the last addToTagSpan
  1582.     extraText = this.inStr.substr(this.tagSpanLastIndex, offset-this.tagSpanLastIndex);
  1583.     this.tagSpan.add(extraText);
  1584.   }
  1585.   this.tagSpan.add(code);
  1586.   this.tagSpanLastIndex = offset + code.length;
  1587. }
  1588.  
  1589. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1590. // Function : TM_addOpenTagToTagSpan
  1591. // Purpose  : Add open tag to the current tag span.  Keep track of nested
  1592. // tags (e.g. <foo><foo></foo></foo>) with the tagSpanCounter.
  1593. // Returns  : true = continue parsing, false = stop parsing
  1594. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1595.  
  1596. function TM_addOpenTagToTagSpan(code, offset, trailingFormat)
  1597. {
  1598.   if (debugTagSpan)
  1599.     alert("addOpenTagToTagSpan..." + code);
  1600.  
  1601.   var openPattern = new RegExp("^<" + this.tagSpanName + "\\b", "i");
  1602.  
  1603.   //if (this.tagSpanCounter == 0) // first tag
  1604.   if (this.tagSpanSnapshot.offset == offset-code.length) // first tag
  1605.     this.tagSpanLastIndex = -1;
  1606.   this.addToTagSpan(code, offset-code.length);
  1607.  
  1608.   var isComplete = (trailingFormat.length > 0 &&
  1609.             trailingFormat[trailingFormat.length-1] == '/');
  1610.   if (!isComplete && (code.search(openPattern) != -1))
  1611.     this.tagSpanCounter++;
  1612.  
  1613.   if (isComplete && this.tagSpanCounter == 0)
  1614.     return this.finishTagSpan();
  1615.  
  1616.   var continueTagSpan = new Object();
  1617.   continueTagSpan.success = false;
  1618.   continueTagSpan.inTagSpan = true;
  1619.   continueTagSpan.reparse = false;
  1620.   return continueTagSpan;
  1621. }
  1622.  
  1623. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1624. // Function : TM_addCloseTagToTagSpan
  1625. // Purpose  : Add close tag to the current tag span.  Keep track of nested
  1626. // tags with the tagSpanCounter.  If this is the end of the tag span, try
  1627. // to translate it.  If translation is impossible, stop parsing (we'll have
  1628. // to start over).
  1629. // Returns  : true = continue parsing, false = stop parsing
  1630. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1631.  
  1632. function TM_addCloseTagToTagSpan(code, offset)
  1633. {
  1634.   if (debugTagSpan)
  1635.     alert("addCloseTagToTagSpan..." + code);
  1636.  
  1637.   var closePattern = new RegExp("^</" + this.tagSpanName + "\\b", "i");
  1638.  
  1639.   this.addToTagSpan(code, offset-code.length);
  1640.   if (code.search(closePattern) != -1)
  1641.     this.tagSpanCounter--;
  1642.  
  1643.   if (this.tagSpanCounter == 0)
  1644.   {
  1645.     return this.finishTagSpan();
  1646.   }
  1647.  
  1648.   var continueTagSpan = new Object();
  1649.   continueTagSpan.success = false;
  1650.   continueTagSpan.inTagSpan = true;
  1651.   continueTagSpan.reparse = false;
  1652.   return continueTagSpan;
  1653. }
  1654.  
  1655. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1656. // Function : TM_finishTagSpan
  1657. // Purpose  : Try to translate the tag span.
  1658. // Returns  : true = continue parsing, false = stop parsing
  1659. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1660.  
  1661. function TM_finishTagSpan()
  1662. {
  1663.   var origPosition = this.translator.getPosition();
  1664.   if (this.inMegaLock)
  1665.   {
  1666.     // If we end up reparsing this tag span because there isn't a
  1667.     // participant match, we need to have already inserted any leading
  1668.     // whitespace into the mega lock before that happens.
  1669.     var preCode = this.inStr.substr(origPosition, this.tagSpanSnapshot.offset-origPosition);
  1670.     this.addToMegaLock(preCode, "", "");
  1671.   }
  1672.  
  1673.   var success = new Object();
  1674.   success.success = true;
  1675.   success.inTagSpan = false;
  1676.   success.reparse = false;
  1677.  
  1678.   var failure = new Object();
  1679.   failure.success = false;
  1680.   failure.inTagSpan = true;
  1681.   failure.reparse = true;
  1682.  
  1683.   var translation;
  1684.   var tagSpanString = this.tagSpan.toString();
  1685.  
  1686.   if (debugTagSpan)
  1687.     alert("finishTagSpan...\n" + tagSpanString);
  1688.  
  1689.   if (this.tagSpanCache) // Use cached translation if available
  1690.   {
  1691.     translation = this.tagSpanCache.getTranslation(tagSpanString);
  1692.     if (translation)
  1693.     {
  1694.       translation = this.correctOutlineIDs(translation);
  1695. //      alert("CACHED TRANSLATION\n==========\n" + tagSpanString +
  1696. //            "\n===========\n" + translation);
  1697.       this.translator.insertTranslation(tagSpanString, this.tagSpanSnapshot.offset, translation);
  1698.       this.inTagSpan = false;
  1699.  
  1700.       return success;
  1701.     }
  1702.   }
  1703.  
  1704.   var index = "tag+" + this.tagSpanName + ":all";
  1705.   var index2 = "tag+*:all";
  1706.   var part = this.getMatchingParticipant(index, index2,
  1707.                        this.tagSpanParts, tagSpanString);
  1708.  
  1709.   if (part != null)
  1710.   {
  1711.     var trans = this.getData(part, tagSpanString);
  1712.  
  1713.     if (trans && trans.type == "external")
  1714.     {
  1715.       trans = evalExternalFunction(trans.display, tagSpanString, this);
  1716.       // External functions for tag spans can return null to force the
  1717.       // various components of the tag span to be parsed separately.
  1718.       if (trans == null)
  1719.         return failure;
  1720.     }
  1721.  
  1722.     if (trans && trans.beginMegaLock)
  1723.     {
  1724.         this.startMegaLock(this.tagSpanSnapshot.offset);
  1725.     }
  1726.  
  1727.     // use AppendText to prevent translated attributes being
  1728.     // appended to the end tag
  1729.     var result = this.translateText(tagSpanString, this.tagSpanSnapshot.offset, trans);
  1730.  
  1731.     if (trans && trans.endMegaLock)
  1732.     {
  1733.         result.translation = this.finishMegaLock(trans.lockAttributes);
  1734.     }
  1735.  
  1736.     if (result.reparse)
  1737.     {
  1738.       if (result.useEditMode)
  1739.       {
  1740.         this.startEditMode(this.tagSpanSnapshot.offset + tagSpanString.length,
  1741.                            tagSpanString,
  1742.                            result.translation);
  1743.       }
  1744.       // We need to leave this.inTagSpan on here, so that the next parse
  1745.       // works on the individual tags instead of the whole span
  1746.       return failure;
  1747.     }
  1748.  
  1749.     if (this.tagSpanCache) // Store translation in cache if available
  1750.     {
  1751.       this.tagSpanCache.setTranslation(tagSpanString, result.translation);
  1752.     }
  1753.  
  1754.     if (this.inMegaLock)
  1755.     {
  1756.       // We already inserted the precode at the top of this function.
  1757.       this.addToMegaLock("", tagSpanString, result.translation);
  1758.     }
  1759.  
  1760.     this.inTagSpan = false;
  1761.     return success;
  1762.   }
  1763.   else
  1764.   {
  1765.     return failure;
  1766.   }
  1767. }
  1768.  
  1769. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1770. // Function : TM_correctOutlineIDs
  1771. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1772. function TM_correctOutlineIDs(translation)
  1773. {
  1774.   var oldBaseId = null;
  1775.   var newBaseId = this.translator.getOutlineId();
  1776.   var outlineId = null;
  1777.   var attr = "mmTranslatedValueOutlineID=\"OUTLINEID=";
  1778.  
  1779.   var translationPieces = translation.split(attr);
  1780.   for (var i = 1; i < translationPieces.length; i++)
  1781.   {
  1782.     translationPieces[i] = 
  1783.         translationPieces[i].replace(/^([0-9]*)\"/, "\"");
  1784.     if (oldBaseId == null)
  1785.         oldBaseId = RegExp.$1;
  1786.     outlineId = RegExp.$1 - oldBaseId + newBaseId;
  1787.     translationPieces[i] = outlineId + translationPieces[i];
  1788.   }
  1789.  
  1790.   this.translator.setOutlineId(outlineId);
  1791.   return translationPieces.join("mmTranslatedValueOutlineID=\"OUTLINEID=");
  1792. }
  1793.  
  1794. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1795. // Function : TM_getMatchingParticipant
  1796. // Purpose  : Find a participant that matches our tag.
  1797. // Arguments: specIndex = specific index (e.g. "tag+foo:all")
  1798. //        genIndex = general index (e.g. "tag+*:all")
  1799. //        partArray = array of available participants
  1800. //        code = stuff to try to match
  1801. // Returns  : true = continue parsing, false = stop parsing
  1802. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1803.  
  1804. function TM_getMatchingParticipant(specIndex, genIndex, partArray, code)
  1805. {
  1806.   var part = null;
  1807.   var arry = translatorInfo[this.index];
  1808.  
  1809.   for (index in partArray)
  1810.   {
  1811.     var possiblePart = partArray[index];
  1812.     var translations = arry[possiblePart].translations;
  1813.     if (translations)
  1814.    {
  1815.       if (translations[specIndex])
  1816.       {
  1817.         // translationType="none" skips the translation
  1818.         if (translations[specIndex].data.type == "none")
  1819.           return null;
  1820.         if (this.searchMatchesCode(possiblePart, code))
  1821.         {
  1822.           this.whereToSearch = specIndex;
  1823.           part = possiblePart;
  1824.           break;
  1825.         }
  1826.       }
  1827.       if (!part)
  1828.       {
  1829.         if (translations[genIndex])
  1830.         {
  1831.           // translationType="none" skips the translation
  1832.           if (translations[genIndex].data.type == "none")
  1833.             return null;
  1834.           if (this.searchMatchesCode(possiblePart, code))
  1835.           {
  1836.             this.whereToSearch = genIndex;
  1837.             part = possiblePart;
  1838.           }
  1839.         }
  1840.       }
  1841.     }
  1842.   }
  1843.   return part;
  1844. }
  1845.  
  1846. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1847. // Function : TM_translateTextSpan
  1848. // Purpose  : translate the text span given the translation rules 
  1849. // Text spans may contain multiple pattern matches, we will translate all
  1850. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1851. function TM_translateTextSpan(code, offset)
  1852. {
  1853.   var part = this.getParticipant(PTYPE_TEXT, code);
  1854.   if (part && part.length)
  1855.   {
  1856.     if (translatorInfo[this.index][part].patterns);
  1857.     {
  1858.       var arry = translatorInfo[this.index][part];
  1859.       for (var patternName in arry.patterns)
  1860.       {
  1861.         var pattern = arry.patterns[patternName];
  1862.         var isRE = arry.isPatternRE[patternName];
  1863.         if (isRE)
  1864.         {
  1865.           var paramNames = arry.paramNames[patternName];
  1866.           var paramArry;
  1867.           if (paramNames)
  1868.             paramArry = paramNames.split(",");
  1869.           else
  1870.             paramArry = Array();
  1871.           var re = pattern;
  1872.           re.lastIndex = 0;
  1873.           //re.compile();
  1874.           var matchesArry;
  1875.           while ((matchesArry = re.exec(code)) != null)
  1876.           {
  1877.             var params = new Array();
  1878.             for (var i = 1; i < matchesArry.length; i++)
  1879.             {
  1880.               if (paramArry && paramArry.length >= i && paramArry[i-1].length)
  1881.               {
  1882.                 params[paramArry[i-1]] = matchesArry[i];
  1883.               }
  1884.             }
  1885.             this.params = params;
  1886.             var trans = this.getData(part, matchesArry[0]);
  1887.             var translate = true;
  1888.             if ((this.translatorClass == "MM_CFML") && ((trans.type == "dynamic data") || (trans.type == "dynamic image")))
  1889.             {
  1890.               translate = !this.CFOutput.IsEmpty();
  1891.               if (translate)
  1892.               {
  1893.                 var queryName = this.CFOutput.Peek();
  1894.                 if (queryName && queryName.length && trans.attributes.indexOf("SOURCE=\"\"") != -1)
  1895.                 {
  1896.                   trans.attributes = trans.attributes.replace(/SOURCE=""/g, "SOURCE=" + queryName);
  1897.                 }
  1898.               }
  1899.             }
  1900.             if (translate)
  1901.             {
  1902.               this.translateText(matchesArry[0], offset + matchesArry.index, trans);
  1903.             }
  1904.             //if we use the exec while loop with a non-global pattern,
  1905.             // we will produce an infinite loop.  exit the loop if not global.
  1906.             if (!re.global)
  1907.             {
  1908.               alert("INTERNAL ERROR: non-global search pattern in participant: " + part);
  1909.               break;
  1910.             }
  1911.           }
  1912.         }
  1913.       }
  1914.     }
  1915.   }
  1916. }
  1917.  
  1918. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1919. // Function : TM_startMegaLock
  1920. // Purpose  : Signals the beginning of a mega lock, where several tags, tag spans,
  1921. // and so forth should be translated and aggregated into a single locked region.
  1922. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1923. function TM_startMegaLock(offset)
  1924. {
  1925.     if (this.inMegaLock)
  1926.         return;
  1927.  
  1928.     if (debugMegaLock)
  1929.         alert("StartMegaLock(" + offset + ")");
  1930.     this.translator.previewMode(true);
  1931.     this.inMegaLock = true;
  1932.     this.megaLockPreCodeOffset = offset;
  1933.     this.megaLockCode = new QuickString();
  1934.     this.megaLockTranslation = new QuickString();
  1935.     this.megaLockSnapshot = new Snapshot(this.enclosingTags, offset);
  1936. }
  1937.  
  1938. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1939. // Function : TM_addToMegaLock
  1940. // Purpose  : Keeps megaLockCode and megaLockTranslation up to date
  1941. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1942. function TM_addToMegaLock(preCode, code, translation)
  1943. {
  1944.     if (!this.inMegaLock)
  1945.         return;
  1946.  
  1947.     if (debugMegaLock)
  1948.         alert("AddToMegaLock\n" +
  1949.         "PreCode...\n" + preCode + "\n" +
  1950.         "Code...\n" + code + "\n" +
  1951.         "Translation...\n" + translation + "\n");
  1952.  
  1953.     // If this is the first translated item, we need to drop any leading
  1954.     // whitespace characters from the code and from the translation
  1955.     if (this.megaLockCode.isEmpty())
  1956.     {
  1957.         var preCodeLength = preCode.length;
  1958.         this.megaLockPreCodeOffset = this.megaLockSnapshot.offset - preCodeLength;
  1959.         this.megaLockCode.add(code);
  1960.         this.megaLockTranslation.add(translation.substr(preCodeLength));
  1961.     }
  1962.     // Otherwise, we want to include them.
  1963.     else
  1964.     {
  1965.         this.megaLockCode.add(preCode);
  1966.         this.megaLockCode.add(code);
  1967.         this.megaLockTranslation.add(translation);
  1968.     }
  1969.  
  1970.     if (debugMegaLock)
  1971.         alert("Code...\n" + this.megaLockCode.toString());
  1972.     if (debugMegaLock)
  1973.         alert("Translation...\n" + this.megaLockTranslation.toString());
  1974. }
  1975.  
  1976. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1977. // Function : TM_finishMegaLock
  1978. // Purpose  : Signals the end of a mega lock
  1979. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1980. function TM_finishMegaLock(lockAttributes)
  1981. {
  1982.     if (!this.inMegaLock)
  1983.         return;
  1984.  
  1985.     if (debugMegaLock)
  1986.         alert("FinishMegaLock\n" +
  1987.         "PreCodeOffset..." + this.megaLockPreCodeOffset + "\n" +
  1988.         "Offset..." + this.megaLockSnapshot.offset + "\n" +
  1989.         "Code...\n" + this.megaLockCode.toString() + "\n" +
  1990.         "Translation...\n" + this.megaLockTranslation.toString());
  1991.  
  1992.     this.translator.previewMode(false);
  1993.     this.translator.resetPosition(this.megaLockPreCodeOffset);
  1994.     var megaLockCodeString = this.megaLockCode.toString();
  1995.     var result = this.translator.translateText(megaLockCodeString, this.megaLockSnapshot.offset, "", "as is", "", "", "", this.megaLockTranslation.toString(), lockAttributes);
  1996.  
  1997.     var endOffset = this.megaLockSnapshot.offset + megaLockCodeString.length;
  1998.     
  1999.     if (this.inEditMode)
  2000.     {
  2001.         this.editModeFullTranslation.add(result);
  2002.         if (endOffset >= this.editModeEndOffset)
  2003.         {
  2004.             this.endEditMode();
  2005.         }
  2006.     }
  2007.  
  2008.     this.translator.resetPosition(endOffset);
  2009.     this.inMegaLock = false;
  2010.     this.megaLockCode = null;
  2011.     this.megaLockTranslation = null;
  2012.     return result;
  2013. }
  2014.  
  2015.  
  2016. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2017. // Function : TM_startEditMode
  2018. // Purpose  : Sets things up when we've finished parsing a control in normal mode and are ready for edit mode.
  2019. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2020. function TM_startEditMode(endOffset, code, translation)
  2021. {
  2022.     this.inEditMode = true;
  2023.     this.mode = "edit";
  2024.     this.editModeEndOffset = endOffset;
  2025.     this.editModeFullCode = code;
  2026.     this.editModeFullTranslation = new QuickString(translation);
  2027. }
  2028.  
  2029.  
  2030. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2031. // Function : TM_endEditMode
  2032. // Purpose  : Wraps things up when we've finished parsing a control in normal mode and in edit mode
  2033. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2034. function TM_endEditMode()
  2035. {
  2036.     var result = this.translator.translateTag("", this.editModeEndOffset, "", "as is", "", "", "", "<mm:toggleVisibility mode=end>", "");
  2037.     this.editModeFullTranslation.add(result);
  2038.  
  2039.     if (this.tagSpanCache)
  2040.     {
  2041.       this.tagSpanCache.setTranslation(this.editModeFullCode, this.editModeFullTranslation.toString());
  2042.     }
  2043.  
  2044.     this.inEditMode = false;
  2045.     this.mode = "preview";
  2046.     this.editModeEndOffset = -1;
  2047.     this.editModeFullCode = null;
  2048.     this.editModeFullTranslation = null;
  2049. }
  2050.  
  2051.  
  2052. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2053. // Function : TM_setDecoration
  2054. // Purpose  : sets decoration on or off.  Should be off for sections of the document
  2055. //        that have been locked by the Live Data Translators.
  2056. // Arguments: decoration - true for sections that have been locked by the Live Data translator
  2057. //        false otherwise.
  2058. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2059. function TM_setDecoration(decoration) 
  2060.   this.translator.setDecoration(decoration);
  2061. }
  2062.  
  2063.  
  2064. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2065. // Function : TM_restartParse
  2066. // Purpose  : restarts Parsing of document this gets called when we encounter a meta tag that is different
  2067. //        than the default encoding.
  2068. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2069. function TM_restartParse() 
  2070.   this.translator.restartParse();
  2071. }
  2072.  
  2073. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2074. // Function : TM_pushOpenTag
  2075. // Purpose  : Updates this.enclosingTags with a new open tag
  2076. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2077. function TM_pushOpenTag(trailingFormat)
  2078. {
  2079.   var tag = this.getCurrentTagName();
  2080.   tag = tag.toLowerCase();
  2081.  
  2082.   var isComplete = (trailingFormat.length > 0 &&
  2083.             trailingFormat[trailingFormat.length-1] == '/');
  2084.   if (!isComplete)
  2085.   {
  2086.     this.enclosingTags.push(tag);
  2087.   }
  2088. }
  2089.  
  2090. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2091. // Function : TM_popCloseTag
  2092. // Purpose  : Updates this.enclosingTags with a new close tag
  2093. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2094. function TM_popCloseTag()
  2095. {
  2096.   var tag = this.getCurrentTagName();
  2097.   tag = tag.toLowerCase();
  2098.   var found = false;
  2099.   while (this.enclosingTags.length > 0 && !found)
  2100.     found = (this.enclosingTags.pop() == tag);
  2101. }
  2102.  
  2103. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2104. // Function : Snapshot class to maintain information needed to reparse document
  2105. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2106. function Snapshot(enclosingTags, offset)
  2107. {
  2108.     this.enclosingTags = enclosingTags.concat();
  2109.     this.offset = offset;
  2110. }
  2111.  
  2112. function TM_takeSnapshot(offset)
  2113. {
  2114.     return new Snapshot(this.enclosingTags, offset);
  2115. }
  2116.  
  2117. function TM_restoreSnapshot(snapshot)
  2118. {
  2119.     this.translator.offsetAdj += snapshot.offset;
  2120.     this.translator.resetPosition(0);
  2121.     this.inStr = this.inStr.substr(snapshot.offset);
  2122.     this.megaLockPreCodeOffset -= snapshot.offset;
  2123.     this.editModeEndOffset -= snapshot.offset;
  2124.     this.enclosingTags = snapshot.enclosingTags;
  2125.     // Do these last, since snapshot may be the same as megaLockSnapshot or tagSpanSnapshot
  2126.     if (this.megaLockSnapshot)
  2127.         this.megaLockSnapshot.offset -= snapshot.offset;
  2128.     if (this.tagSpanSnapshot)
  2129.         this.tagSpanSnapshot.offset -= snapshot.offset;
  2130. }
  2131.  
  2132. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2133. // Function : Stack Class to maintain cfOutput query names
  2134. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2135. function Stack()
  2136. {
  2137. // Members
  2138.   this.data = new Array(50);
  2139.   this.tos = -1;
  2140.   Stack.prototype.Push      = Stack_Push;
  2141.   Stack.prototype.Pop       = Stack_Pop;
  2142.   Stack.prototype.Peek      = Stack_Peek;
  2143.   Stack.prototype.IsEmpty     = Stack_IsEmpty;
  2144. }
  2145.  
  2146. function Stack_Push(value)
  2147. {
  2148.   if (this.tos < -1)
  2149.   {
  2150.     this.tos = -1;
  2151.   }
  2152.   this.tos += 1;
  2153.   this.data[this.tos] = value;
  2154. }
  2155.  
  2156. function Stack_Pop()
  2157. {
  2158.   var top = null;
  2159.   if (this.tos >= 0)
  2160.   {
  2161.     top = this.data[this.tos];
  2162.     this.tos -= 1;
  2163.   }
  2164.  
  2165.   return top;
  2166. }
  2167.  
  2168. function Stack_Peek()
  2169. {
  2170.   var top = null;
  2171.   if (this.tos >= 0)
  2172.   {
  2173.     top = this.data[this.tos];
  2174.   }
  2175.  
  2176.   return top;
  2177. }
  2178.  
  2179. function Stack_IsEmpty()
  2180. {
  2181.   if (this.tos < 0)
  2182.   {
  2183.     return true;
  2184.   }
  2185.  
  2186.   return false;
  2187. }
  2188.